import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit';
import { RootState, AppThunk } from '../../app/store';
import { fetchCount } from './counterAPI';

export interface ModelInfo {
  modelName: string
  [key: string]: any
}

export interface CounterState {
  value: number;
  status: 'idle' | 'loading' | 'failed';
  modelInfo?: ModelInfo
  modelInfoLoading?: boolean
}

const initialState: CounterState = {
  value: 0,
  status: 'idle',
};

// The function below is called a thunk and allows us to perform async logic. It
// can be dispatched like a regular action: `dispatch(incrementAsync(10))`. This
// will call the thunk with the `dispatch` function as the first argument. Async
// code can then be executed and other actions can be dispatched. Thunks are
// typically used to make async requests.
// type 前缀，type 被多个 thunk 使用，会造成状态混乱
export const incrementAsync = createAsyncThunk(
  'counter/fetchCount',
  async (amount: number, thunkApi) => {
    const response = await fetchCount(amount);

    const t2 = await thunkApi.dispatch(incrementAsync2(amount));
    console.log(t2.payload as number, t2)

    // The value we return becomes the `fulfilled` action payload
    // 如果需要判定失败，处理错误，抛出错误
    const error = { code: 200, msg: '添加失败' }
    if (amount === 2) {
      // errorHandle(error);

      throw error;
    }

    return response.data;
  }
);

export const incrementAsync2 = createAsyncThunk(
  'counter/fetchCount',
  async (amount: number) => {
    const response = await fetchCount(amount);
    // The value we return becomes the `fulfilled` action payload
    // 如果需要判定失败，处理错误，抛出错误
    // const error = { code: 200, msg: '添加失败' }
    // if (amount === 2) {
    //   // errorHandle(error);

    //   throw error;
    // }

    return response.data;
  }
);

export const saveModelFormAsync = createAsyncThunk<ModelInfo, { resolve?: () => void } & Partial<ModelInfo>>(
  'model/saveModel',
  async ({ resolve, ...modelForm }) => {
    const response = await fetchCount();

    resolve?.()
    return { ...modelForm } as ModelInfo
  }
)

export const counterSlice = createSlice({
  name: 'counter',
  initialState,
  // The `reducers` field lets us define reducers and generate associated actions
  // 同步修改 state, state 是最新的应用状态
  // 在 redux-devtool 中 type 是 conter(slice name)/increment(reducer name)
  // redux-devtool 中，接收浏览器中所有的实例
  reducers: {
    increment: (state) => {
      // Redux Toolkit allows us to write "mutating" logic in reducers. It
      // doesn't actually mutate the state because it uses the Immer library,
      // which detects changes to a "draft state" and produces a brand new
      // immutable state based off those changes
      state.value += 1;
    },
    decrement: (state) => {
      state.value -= 1;
    },
    // Use the PayloadAction type to declare the contents of `action.payload`
    incrementByAmount: (state, action: PayloadAction<number>) => {
      state.value += action.payload;
    },
  },
  // The `extraReducers` field lets the slice handle actions defined elsewhere,
  // including actions generated by createAsyncThunk or in other slices.
  // 异步修改 state，提供一组操作，请求前、请求成功、请求失败
  // 如果需要让接口失败，可以在 incrementAsync 中 throw 错误
  extraReducers: (builder) => {
    builder
      .addCase(incrementAsync.pending, (state) => {
        state.status = 'loading';
      })
      .addCase(incrementAsync.fulfilled, (state, action) => {
        state.status = 'idle';
        state.value += action.payload;
      })
      .addCase(incrementAsync.rejected, (state, action) => {
        state.status = 'failed';
      });

    builder
      .addCase(saveModelFormAsync.pending, (state) => {
        state.modelInfoLoading = true;
      })
      .addCase(saveModelFormAsync.fulfilled, (state, action) => {
        state.modelInfoLoading = false;
        state.modelInfo = action.payload;
      })
      .addCase(saveModelFormAsync.rejected, (state, action) => {
        state.modelInfoLoading = false;
      })
  },
});

export const { increment, decrement, incrementByAmount } = counterSlice.actions;
export const counterAction = counterSlice.actions

// The function below is called a selector and allows us to select a value from
// the state. Selectors can also be defined inline where they're used instead of
// in the slice file. For example: `useSelector((state: RootState) => state.counter.value)`
export const selectCount = (state: RootState) => state.counter.value;

// We can also write thunks by hand, which may contain both sync and async logic.
// Here's an example of conditionally dispatching actions based on current state.
export const incrementIfOdd =
  (amount: number): AppThunk =>
    (dispatch, getState) => {
      const currentValue = selectCount(getState());
      if (currentValue % 2 === 1) {
        dispatch(incrementByAmount(amount));
      }
    };

export default counterSlice.reducer;
